// Combining data pump/function
// Copyright 2006 (C) Ralph Thomas

#include <datapumps/combine.h>
#include <binder.hpp>
#include <vector>

#include <iostream>

namespace datapumps {
	class combine_datapump_t : public adobe::binder_t {
		typedef std::vector<adobe::binder_ptr_t> binder_list_t;
		binder_list_t 				binders_m;
		adobe::binder_helper_t			active_helper_m;
		bool 					active_m;
		adobe::sheet_t::monitor_active_t	active_monitor_m;
		//
		// Required for copying.
		//
		adobe::sheet_t&				sheet_m;
		adobe::value_t				active_value_m;
		adobe::array_t				array_m;
		//
		/// Updates the active state of this datapump.
		//
		void update_active( const adobe::value_t& val ) {
			bool active( active_m );
			if( !val.get( active ) ) return;
			if( active == active_m ) return;
			active_m = active;
			if( active_monitor_m )
				active_monitor_m( active );
		}
		//
		/// Read in all of the datapumps from the given array.
		//
		void load_datapump( const adobe::value_t& val ) {
			adobe::binder_ptr_t pump;
			if( val.get( pump ) ) binders_m.push_back( pump );
		}
	  public:
		combine_datapump_t( const adobe::dictionary_t& dict, adobe::sheet_t& sheet )
		: active_helper_m( sheet ), active_m( true ), sheet_m( sheet ) {
			//
			// Attempt to get the array of datapumps and the active datapump
			// if we can. We can function with only one.
			//
			dict.get( adobe::static_name_t( "actions" ), array_m );
			adobe::for_each( array_m, boost::bind( &combine_datapump_t::load_datapump, this, _1 ) );
			dict.get( adobe::static_name_t( "active" ), active_value_m );
			active_helper_m.initialize( active_value_m,
				boost::bind( &combine_datapump_t::update_active, this, _1 ), 0 );
		}
		combine_datapump_t( const adobe::value_t& active, const adobe::array_t& array, adobe::sheet_t& sheet )
		: active_helper_m( sheet ), active_m( true ), sheet_m( sheet ), active_value_m( active ), array_m( array ) {
			adobe::for_each( array_m, boost::bind( &combine_datapump_t::load_datapump, this, _1 ) );
			active_helper_m.initialize( active_value_m,
				boost::bind( &combine_datapump_t::update_active, this, _1 ), 0 );
		}
		virtual ~combine_datapump_t() {}
		virtual void set( const adobe::value_t& ) {
			throw std::runtime_error( "combine datapump is not settable" );
		}
		virtual void set_signals( const adobe::sheet_t::monitor_value_t&,
			const adobe::sheet_t::monitor_active_t& monitor_active ) {
			active_monitor_m = monitor_active;
			if( active_monitor_m ) active_monitor_m( active_m );
		}
		virtual void substitute( const adobe::name_t& name, const adobe::value_t& val ) {
			active_helper_m.substitute( name, val );
		}
		virtual void invoke() {
			adobe::for_each( binders_m, boost::bind( &adobe::binder_t::invoke, _1 ) );
		}
		virtual adobe::binder_ptr_t copy() const {
			return adobe::binder_ptr_t( new combine_datapump_t( active_value_m, array_m, sheet_m ) );
		}
	};
	adobe::value_t make_combine_datapump( const adobe::dictionary_t& parameters, adobe::sheet_t& sheet ) {
		return adobe::value_t( adobe::binder_ptr_t( new combine_datapump_t( parameters, sheet ) ) );
	}
	adobe::value_t make_combine_datapump( const adobe::array_t& parameters, adobe::sheet_t& sheet ) {
		return adobe::value_t( adobe::binder_ptr_t( new combine_datapump_t( adobe::value_t( true ), parameters, sheet ) ) );
	}
};

